﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace Quail.Helpers
{
    public static class Http
    {
        public static int Timeout = 60000;




        static Http()
        {
            ServicePointManager.ServerCertificateValidationCallback +=
            delegate(
                object sender,
                X509Certificate certificate,
                X509Chain chain,
                SslPolicyErrors sslPolicyErrors)
            {
                return true;
            };
        }

        


        /// <summary>
        /// Encodes a string using HTML encoding
        /// </summary>
        /// <param name="str">string to encode</param>
        /// <returns>the encoded string</returns>
        public static string HtmlEncode(string str)
        {
            return HttpUtility.HtmlEncode(str);
        }

        /// <summary>
        /// Decodes an HTML-encoded string
        /// </summary>
        /// <param name="str">The string to decode</param>
        /// <returns>the decoded string</returns>
        public static string HtmlDecode(string str)
        {
            return HttpUtility.HtmlDecode(str);
        }

        /// <summary>
        /// Opens the URL and returns the time it took in ms
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static long GetResponseTime(string url)
        {
            var sw = new Stopwatch();
            var req = WebRequest.Create(url);
            req.Timeout = Timeout;

            sw.Start();
            using (var res = req.GetResponse())
            {
                var data = new byte[1024];
                using (var str = res.GetResponseStream())
                {
                    for (; ; )
                    {
                        if (str.Read(data, 0, 1024) == 0)
                            break;
                    }
                }
            }

            sw.Stop();

            return sw.ElapsedMilliseconds;
        }


        /// <summary>
        /// Converts a name value collection into a query string parameters
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static string ToQueryString(this NameValueCollection parameters)
        {
            return String.Join("&",
                               parameters.AllKeys
                                   .Select(key => key + "=" + HttpUtility.UrlEncode(parameters[key]))
                                   .ToArray());
        }

        /// <summary>
        /// Converts a KeyValuePair collection into a query string parameters
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public static string ToQueryString(this IEnumerable<KeyValuePair<string, string>> parameters)
        {
            return String.Join("&",
                               parameters
                                   .Select(p => p.Key + "=" + HttpUtility.UrlEncode(p.Value))
                                   .ToArray());
        }

        /// <summary>
        /// Gets the response object
        /// </summary>
        /// <param name="url"></param>
        /// <returns>The status code</returns>
        public static HttpStatusCode GetResponseStatus(string url)
        {
            var req = WebRequest.Create(url);
            req.Timeout = Timeout;

            try
            {
                HttpStatusCode code;
                var res = (HttpWebResponse)req.GetResponse();
                using (res)
                {
                    var data = new byte[1024];
                    using (var str = res.GetResponseStream())
                    {
                        for (; ; )
                        {
                            if (str.Read(data, 0, 1024) == 0)
                                break;
                        }
                    }
                    code = res.StatusCode;
                }

                return code;
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.ProtocolError || ex.Status == WebExceptionStatus.ConnectFailure)
                    return HttpStatusCode.Unauthorized;

                throw;
            }
        }

        /// <summary>
        /// Gets the response text from a specific url
        /// </summary>
        /// <param name="url">The url to call</param>
        /// <returns>The http request response text</returns>
        public static string GetResponseText(string url)
        {
            var req = (HttpWebRequest)WebRequest.Create(url);
            req.Timeout = Timeout;
            return GetResponseText(req);
        }

        /// <summary>
        /// Gets the response text and sets the referer to whatever you want
        /// </summary>
        /// <param name="url">The url to call</param>
        /// <param name="referer">The referer to call it as</param>
        /// <returns>The http request response text</returns>
        public static string GetResponseText(string url, string referer)
        {
            var req = (HttpWebRequest) WebRequest.Create(url);
            req.Timeout = Timeout;
            req.Referer = referer;
            
            return GetResponseText(req);
        }




        /// <summary>
        /// Duplicates User Agent and gets the response text.
        /// </summary>
        /// <param name="url">The url to call</param>
        /// <param name="browser">The browser object for the current session</param>
        /// <param name="modifyRequest">Action that can perform operations on an HttpWebRequest</param>
        /// <returns>The http request response text</returns>
        public static string GetResponseText(string url, IWebBrowser browser, Action<HttpWebRequest> modifyRequest)
        {
            var req = (HttpWebRequest)WebRequest.Create(url);
            req.UserAgent = ((WebBrowser)browser).GetUserAgent();
            modifyRequest(req);
            return GetResponseText(req);
        }




        /// <summary>
        /// Gets the response text from a specific web request
        /// </summary>
        /// <param name="request">The web request</param>
        /// <returns>The http request response text</returns>
        public static string GetResponseText(WebRequest request)
        {
            var text = string.Empty;
            const int size = 1024;

            using (var res = request.GetResponse())
            {
                var data = new Char[size];
                using (var str = res.GetResponseStream())
                {
                    using (var reader = new StreamReader(str, Encoding.UTF8))
                    {
                        var count = reader.Read(data, 0, size);
                        while (count > 0)
                        {
                            text += new String(data, 0, count);
                            count = reader.Read(data, 0, size);
                        }
                        reader.Close();
                    }
                    str.Close();
                }
                res.Close();
            }

            return text;            
        }
    }
}
